home *** CD-ROM | disk | FTP | other *** search
/ Java Programmer's Toolkit / Java Programmer's Toolkit.iso / gs3.53 / gs_setpd.ps < prev    next >
Text File  |  1996-01-10  |  20KB  |  623 lines

  1. %    Copyright (C) 1994, 1995 Aladdin Enterprises.  All rights reserved.
  2. % This file is part of Aladdin Ghostscript.
  3. % Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  4. % or distributor accepts any responsibility for the consequences of using it,
  5. % or for whether it serves any particular purpose or works at all, unless he
  6. % or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  7. % License (the "License") for full details.
  8. % Every copy of Aladdin Ghostscript must include a copy of the License,
  9. % normally in a plain ASCII text file named PUBLIC.  The License grants you
  10. % the right to copy, modify and redistribute Aladdin Ghostscript, but only
  11. % under certain conditions described in the License.  Among other things, the
  12. % License requires that the copyright notice and this notice be preserved on
  13. % all copies.
  14.  
  15. % The current implementation of setpagedevice has the following limitations:
  16. %    - It doesn't attempt to "interact with the user" for Policy = 2.
  17.  
  18. languagelevel 1 .setlanguagelevel
  19. level2dict begin
  20.  
  21. % ---------------- Redefinitions ---------------- %
  22.  
  23. % Redefine .beginpage and .endpage so that they call BeginPage and
  24. % EndPage respectively if appropriate.
  25.  
  26. /.beginpage
  27.  { .currentshowpagecount
  28.     { .currentpagedevice pop /BeginPage .knownget { exec } { pop } ifelse }
  29.    if
  30.  } bind odef
  31.  
  32. /.endpage
  33.  { .currentshowpagecount
  34.     { exch .currentpagedevice pop /EndPage .knownget
  35.        { exec }
  36.        { exch pop 2 ne }
  37.       ifelse
  38.     }
  39.     { 2 ne
  40.     }
  41.    ifelse
  42.  } bind odef
  43.  
  44. % Define interpreter callouts for handling gstate-saving operators,
  45. % to make sure that they create a page device dictionary for use by
  46. % the corresponding gstate-restoring operator.
  47. % We'd really like to avoid the cost of doing this, but we don't see how.
  48. % The names %gsavepagedevice, %savepagedevice, %gstatepagedevice,
  49. % %copygstatepagedevice, and %currentgstatepagedevice are known to the
  50. % interpreter.
  51.  
  52. (%gsavepagedevice) cvn
  53.  { currentpagedevice pop gsave
  54.  } bind def
  55.  
  56. (%savepagedevice) cvn
  57.  { currentpagedevice pop save
  58.  } bind def
  59.  
  60. (%gstatepagedevice) cvn
  61.  { currentpagedevice pop gstate
  62.  } bind def
  63.  
  64. (%copygstatepagedevice) cvn
  65.  { currentpagedevice pop copy
  66.  } bind def
  67.  
  68. (%currentgstatepagedevice) cvn
  69.  { currentpagedevice pop currentgstate
  70.  } bind def
  71.  
  72. % Define interpreter callouts for handling gstate-restoring operators
  73. % when the current page device needs to be changed.
  74. % The names %grestorepagedevice, %grestoreallpagedevice,
  75. % %restorepagedevice, and %setgstatepagedevice are known to the interpreter.
  76.  
  77. /.installpagedevice
  78.  {    % Since setpagedevice doesn't create new device objects,
  79.     % we must (carefully) reinstall the old parameters in
  80.     % the same device.
  81.    .currentpagedevice pop null currentdevice null .trysetparams
  82.    dup type /booleantype eq
  83.     { pop pop }
  84.     {        % This should never happen!
  85.       DEBUG { (Error in .trysetparams!\n) print pstack flush } if
  86.       cleartomark pop pop pop
  87.       /.installpagedevice cvx /rangecheck signalerror
  88.     }
  89.    ifelse pop pop
  90.    erasepage initgraphics .beginpage
  91.  } bind def
  92.  
  93. /.uninstallpagedevice
  94.  { 2 .endpage { .currentnumcopies false .outputpage } if
  95.    nulldevice
  96.  } bind def
  97.  
  98. (%grestorepagedevice) cvn
  99.  { .uninstallpagedevice grestore .installpagedevice
  100.  } bind def
  101.  
  102. (%grestoreallpagedevice) cvn
  103.  { .uninstallpagedevice grestore .installpagedevice grestoreall
  104.  } bind def
  105.  
  106. (%restorepagedevice) cvn
  107.  { .uninstallpagedevice grestore .installpagedevice restore
  108.  } bind def
  109.  
  110. (%setgstatepagedevice) cvn
  111.  { .uninstallpagedevice setgstate .installpagedevice
  112.  } bind def
  113.  
  114. % Redefine .currentnumcopies so it consults the NumCopies device parameter.
  115. /.numcopiesdict mark
  116.   /NumCopies dup
  117. .dicttomark readonly def
  118.  
  119. /.currentnumcopies
  120.  { currentdevice //.numcopiesdict .getdeviceparams
  121.    dup type /integertype eq
  122.     { exch pop exch pop }
  123.     { cleartomark #copies }
  124.    ifelse
  125.  } bind odef
  126.  
  127. % ---------------- Auxiliary definitions ---------------- %
  128.  
  129. % Define the required attributes of all page devices, and their default values.
  130. % We don't include attributes such as .MediaSize, which all devices
  131. % are guaranteed to supply on their own.
  132. /.defaultpolicies mark
  133.   /PolicyNotFound 1
  134.   /PageSize 0
  135.   /PolicyReport {pop} bind
  136. .dicttomark readonly def
  137. /.requiredattrs mark
  138.   /PageOffset [0 0] readonly
  139. % We define InputAttributes and OutputAttributes with a single
  140. % dummy media type that handles pages of any size.
  141. % Devices that care will override this.
  142.   /InputAttributes mark 0
  143.     mark /PageSize [0 dup 16#7ffff dup] .dicttomark readonly
  144.   .dicttomark readonly
  145.   (%MediaSource) 0
  146.   /OutputAttributes mark 0
  147.     mark .dicttomark readonly
  148.   .dicttomark readonly
  149.   (%MediaDestination) 0
  150.   /Install {.callinstall} bind
  151.   /BeginPage {.callbeginpage} bind
  152.   /EndPage {.callendpage} bind
  153.   /Policies .defaultpolicies
  154. .dicttomark readonly def
  155.  
  156. % Define currentpagedevice so it creates the dictionary on demand if needed,
  157. % adding all the required entries defined just above.
  158. % We have to deal specially with entries that the driver may change
  159. % on its own.
  160. /.dynamicppkeys mark
  161.   /PageCount dup
  162. .dicttomark readonly def
  163. /.makecurrentpagedevice        % - .makecurrentpagedevice <dict>
  164.  { currentdevice null .getdeviceparams
  165.     % In case of duplicate keys, .dicttomark takes the entry
  166.     % lower on the stack, so we can just append the defaults here.
  167.    .requiredattrs { } forall .dicttomark
  168.    dup .setpagedevice
  169.  } bind def
  170. /currentpagedevice
  171.  { .currentpagedevice
  172.     { dup length 0 eq
  173.        { pop .makecurrentpagedevice
  174.        }
  175.        {    % If any of the dynamic keys have changed,
  176.         % we must update the page device dictionary.
  177.      currentdevice //.dynamicppkeys .getdeviceparams .dicttomark
  178.       {    % Stack: current key value
  179.         2 index 2 index .knownget { 1 index ne } { true } ifelse
  180.          { 2 index wcheck not
  181.         {    % This is the first entry being updated.
  182.             % Copy the dictionary to make it writable.
  183.           3 -1 roll dup length dict copy
  184.           3 1 roll
  185.         }
  186.            if
  187.            2 index 3 1 roll put
  188.          }
  189.          { pop pop
  190.          }
  191.         ifelse
  192.       }
  193.      forall
  194.         % The dictionary will be writable iff we copied it
  195.         % to update some entries.  If so, .setpagedevice will
  196.         % make it read-only again.
  197.      dup wcheck { .setpagedevice .currentpagedevice pop } if
  198.        }
  199.       ifelse
  200.     }
  201.    if
  202.  } bind odef
  203.  
  204. % The implementation of setpagedevice is quite complex.  Currently,
  205. % everything but the media matching algorithm is implemented here.
  206.  
  207. % By default, we only present the requested changes to the device,
  208. % but there are some parameters that require special merging action.
  209. % Define those parameters here, with the procedures that do the merging.
  210. % The procedures are called as follows:
  211. %    <merged> <key> <new_value> -proc- <merged> <key> <new_value'>
  212. /.mergespecial mark
  213.   /InputAttributes
  214.    { dup null eq
  215.       { pop null
  216.       }
  217.       { 3 copy pop .knownget
  218.      { dup null eq
  219.         { pop dup length dict }
  220.         { dup length 2 index length add dict copy }
  221.        ifelse
  222.      }
  223.      { dup length dict
  224.      }
  225.         ifelse copy readonly
  226.       }
  227.      ifelse
  228.    } bind
  229.   /OutputAttributes 1 index
  230.   /Policies
  231.     { 3 copy pop .knownget
  232.        { dup length 2 index length add dict copy }
  233.        { dup length dict }
  234.       ifelse copy readonly
  235.     } bind
  236. .dicttomark readonly def
  237.  
  238. % Define the keys used in input attribute matching.
  239. /.inputattrkeys [
  240.   /PageSize /MediaColor /MediaWeight /MediaType /InsertSheet
  241. ] readonly def
  242. % Define other keys used in media selection.
  243. /.inputselectionkeys [
  244.   /MediaPosition /Orientation
  245. ] readonly def
  246.  
  247. % Define the keys used in output attribute matching.
  248. /.outputattrkeys [
  249.   /OutputType
  250. ] readonly def
  251.  
  252. % Define all the parameters that should always be copied to the merged
  253. % dictionary.
  254. /.copiedkeys [
  255.   /OutputDevice
  256.   .mergespecial { pop } forall
  257.   .inputattrkeys aload pop
  258.   .inputselectionkeys aload pop
  259.   .outputattrkeys aload pop
  260. ] readonly def
  261.  
  262. % Define the parameters that should not be presented to the device.
  263. % The procedures are called as follows:
  264. %    <merged> <key> <value> -proc-
  265. % The procedure leaves all its operands on the stack and returns
  266. % true iff the key/value pair should be presented to .putdeviceparams.
  267. /.presentspecial mark
  268.   .dynamicppkeys { pop false } forall
  269.             % We must ignore an explicit request for .MediaSize,
  270.             % because media matching always handles this.
  271.   /.MediaSize false
  272.   /Name false
  273.   /OutputDevice false
  274.   /PageOffset false
  275.   /PageSize false        % obsolete alias for .MediaSize
  276.   /InputAttributes false
  277.   .inputattrkeys
  278.     { dup /PageSize eq
  279.        { pop }
  280.        { { 2 index /InputAttributes .knownget { null eq } { true } ifelse } }
  281.       ifelse
  282.     }
  283.   forall
  284.   .inputselectionkeys { false } forall
  285.   /OutputAttributes false
  286.   .outputattrkeys
  287.     { { 2 index /OutputAttributes .knownget { null eq } { true } ifelse } }
  288.   forall
  289.   /Install false
  290.   /BeginPage false
  291.   /EndPage false
  292.   /Policies false
  293.     % Our extensions:
  294.   /HWColorMap
  295.     {            % HACK: don't transmit the color map, because
  296.             % window systems can change the color map on their own
  297.             % incrementally.  Someday we'll have a better
  298.             % solution for this....
  299.       false
  300.     }
  301.   /ViewerPreProcess false
  302. .dicttomark readonly def
  303.  
  304. % Define access to device defaults.
  305. /.defaultdevicename defaultdevice .devicename def
  306. /.defaultdeviceparams
  307.  { finddevice null .getdeviceparams
  308.  } bind def
  309.  
  310. % Select media (input or output).  The hard work is done in an operator:
  311. %    <pagedict> <attrdict> <policydict> <keys> .matchmedia <key> true
  312. %    <pagedict> <attrdict> <policydict> <keys> .matchmedia false
  313. %    <pagedict> null <policydict> <keys> .matchmedia null true
  314. /.selectmedia        % <orig> <request> <merged> <failed>     <-- retained
  315.             %   <attrdict> <policydict> <attrkeys> <mediakey>
  316.             %   .selectmedia
  317.  { 5 index 5 -2 roll 4 index .matchmedia
  318.         % Stack: orig request merged failed attrkeys mediakey
  319.         %   (key true | false)
  320.     { 4 index 3 1 roll put pop
  321.     }
  322.     {    % Adobe's implementations have a "big hairy heuristic"
  323.     % to choose the set of keys to report as having failed the match.
  324.     % For the moment, we report any keys that are in the request
  325.     % and don't have the same value as in the original dictionary.
  326.       5 index 1 index .knownget
  327.        { 4 index 3 1 roll put }
  328.        { 3 index exch undef }
  329.       ifelse
  330.        {    % Stack: <orig> <request> <merged> <failed> <attrkey>
  331.      3 index 1 index .knownget
  332.       { 5 index 2 index .knownget { ne } { pop true } ifelse }
  333.       { true }
  334.      ifelse        % Stack: ... <failed> <attrkey> <report>
  335.       { 2 copy /rangecheck put }
  336.      if pop
  337.        }
  338.       forall
  339.     }
  340.    ifelse
  341.  } bind def
  342.  
  343. % Apply Policies to any unprocessed failed requests.
  344. % As we process each request entry, we replace the error name
  345. % in the <failed> dictionary with the policy value,
  346. % and we replace the key in the <merged> dictionary with its prior value
  347. % (or remove it if it had no prior value).
  348. /.applypolicies        % <orig> <merged> <failed> .applypolicies
  349.             %   <orig> <merged'> <failed'>
  350.  { 1 index /Policies get 1 index
  351.     { type /integertype eq
  352.        { pop        % already processed
  353.        }
  354.        { 2 copy .knownget not { 1 index /PolicyNotFound get } if
  355.             % Stack: <orig> <merged> <failed> <Policies> <key>
  356.             %   <policy>
  357.      dup 1 ne
  358.       {    % Set errorinfo and signal a configurationerror.
  359.         % Note that we currently treat all Policy values other than 1
  360.         % the same as 0.
  361.         pop dup 4 index exch get 2 array astore
  362.         $error /errorinfo 3 -1 roll put
  363.         cleartomark
  364.         /setpagedevice load /configurationerror signalerror
  365.       }
  366.       {    % Roll back the failed request to its previous status.
  367. DEBUG { (Rolling back.\n) print pstack flush } if
  368.         3 index 2 index 3 -1 roll put
  369.         4 index 1 index .knownget
  370.          { 4 index 3 1 roll put }
  371.          { 3 index exch undef }
  372.         ifelse
  373.       }
  374.      ifelse
  375.        }
  376.       ifelse
  377.     }
  378.    forall pop
  379.  } bind def
  380.  
  381. % Prepare to present parameters to the device, by spreading them onto the
  382. % operand stack and removing any that shouldn't be presented.
  383. /.prepareparams        % <params> .prepareparams -mark- <key1> <value1> ...
  384.  { mark exch dup
  385.     {            % Stack: -mark- key1 value1 ... merged key value
  386.       .presentspecial 2 index .knownget
  387.        { exec { 3 -1 roll } { pop pop } ifelse }
  388.        { 3 -1 roll }
  389.       ifelse
  390.     }
  391.    forall pop
  392.  } bind def
  393.  
  394. % Put device parameters without resetting currentpagedevice.
  395. % (.putdeviceparams clears the current page device.)
  396. /.putdeviceparamsonly    % <device> <Policies|null> <require_all> -mark-
  397.             %   <key1> <value1> ... .putdeviceparamsonly
  398.             % On success: <device> <eraseflag>
  399.             % On failure: <device> <Policies|null> <req_all> -mark-
  400.             %   <key1> <error1> ...
  401.  { .currentpagedevice
  402.     { counttomark 4 add 1 roll .putdeviceparams
  403.       dup type /booleantype eq { 3 } { counttomark 5 add } ifelse -1 roll
  404.       .setpagedevice
  405.     }
  406.     { pop .putdeviceparams
  407.     }
  408.    ifelse
  409.  } bind def
  410.  
  411. % Try setting the device parameters from the merged request.
  412. /.trysetparams        % <merged> <(ignored)> <device> <Policies>
  413.             %   .trysetparams
  414.  { true 4 index .prepareparams
  415.             % Add the computed .MediaSize.
  416.             % Stack: merged (ignored) device Policies -true-
  417.             %   -mark- key1 value1 ...
  418.    counttomark 5 add index .computemediasize
  419.    exch pop exch pop /.MediaSize exch
  420. DEBUG { (Putting.\n) print pstack flush } if
  421.    .putdeviceparamsonly
  422. DEBUG { (Result of putting.\n) print pstack flush } if
  423.  } bind def
  424.  
  425. % Compute the media size and initial matrix from a merged request (after
  426. % media selection).
  427. /.computemediasize    % <request> .computemediasize
  428.             %   <request> <matrix> <[width height]>
  429.  { dup /PageSize get                    % requested page size
  430.    1 index /InputAttributes get
  431.      2 index (%MediaSource) get get /PageSize get    % media size
  432.                             % (may be a range)
  433.    2 index /Policies get
  434.      dup /PageSize .knownget
  435.       { exch pop } { /PolicyNotFound get } ifelse    % PageSize policy,
  436.                             % affects scaling
  437.    3 index /Orientation .knownget not { null } if
  438.    matrix .matchpagesize pop        % (can't fail)
  439.    2 array astore
  440.  } bind def
  441.  
  442. % ---------------- setpagedevice itself ---------------- %
  443.  
  444. /setpagedevice
  445.  { mark exch currentpagedevice
  446.  
  447.         % Check whether we are changing OutputDevice;
  448.         % also handle the case where the current device
  449.         % is not a page device.
  450.         % Stack: mark <request> <current>
  451. DEBUG { (Checking.\n) print pstack flush } if
  452.  
  453.    dup /OutputDevice .knownget
  454.     {        % Current device is a page device.
  455.       2 index /OutputDevice .knownget
  456.        {    % A specific OutputDevice was requested.
  457.      2 copy eq
  458.       { pop pop null }
  459.       { exch pop }
  460.      ifelse
  461.        }
  462.        { pop null
  463.        }
  464.       ifelse
  465.     }
  466.     {        % Current device is not a page device.
  467.         % Use the default device.
  468.       1 index /OutputDevice .knownget not { .defaultdevicename } if
  469.     }
  470.    ifelse
  471.    dup null eq
  472.     { pop
  473.     }
  474.     { exch pop .defaultdeviceparams
  475.         % In case of duplicate keys, .dicttomark takes the entry
  476.         % lower on the stack, so we can just append the defaults here.
  477.       .requiredattrs { } forall .dicttomark
  478.     }
  479.    ifelse
  480.  
  481.         % Check whether a viewer wants to intervene.
  482.         % We must check both the request (which takes precedence)
  483.         % and the current dictionary.
  484.         % Stack: mark <request> <orig>
  485.    exch dup /ViewerPreProcess .knownget
  486.     { exec }
  487.     { 1 index /ViewerPreProcess .knownget { exec } if }
  488.    ifelse exch
  489.  
  490.         % Construct a merged request from the actual request plus
  491.         % any keys that should always be propagated.
  492.         % Stack: mark <request> <orig>
  493. DEBUG { (Merging.\n) print pstack flush } if
  494.  
  495.    exch 1 index length 1 index length add dict
  496.    .copiedkeys
  497.     {        % Stack: <orig> <request> <merged> <key>
  498.       3 index 1 index .knownget { 3 copy put pop } if pop
  499.     }
  500.    forall
  501.         % Stack: <orig> <request> <merged>
  502.    dup 2 index
  503.     {        % stack: <orig> <request> <merged> <merged> <rkey> <rvalue>
  504.       .mergespecial 2 index .knownget { exec } if
  505.       put dup
  506.     }
  507.    forall pop
  508.         % Hack: if FIXEDRESOLUTION is true, discard any attempt to
  509.         % change HWResolution.
  510.    FIXEDRESOLUTION { dup /HWResolution undef } if
  511.  
  512.         % Select input and output media.
  513.         % Stack: mark <orig> <request> <merged>
  514. DEBUG { (Selecting.\n) print pstack flush } if
  515.  
  516.    0 dict    % <failed>
  517.    1 index /InputAttributes .knownget
  518.     { 2 index /Policies get
  519.       .inputattrkeys (%MediaSource) cvn .selectmedia
  520.     } if
  521.    1 index /OutputAttributes .knownget
  522.     { 2 index /Policies get
  523.       .outputattrkeys (%MediaDestination) cvn .selectmedia
  524.      } if
  525.    3 -1 roll 4 1 roll        % temporarily swap orig & request
  526.    .applypolicies
  527.    3 -1 roll 4 1 roll        % swap back
  528.  
  529.         % Construct the new device, and attempt to set its attributes.
  530.         % Stack: mark <orig> <request> <merged> <failed>
  531. DEBUG { (Constructing.\n) print pstack flush } if
  532.  
  533.    currentdevice .devicename 2 index /OutputDevice get eq
  534.     { currentdevice }
  535.     { 1 index /OutputDevice get finddevice }
  536.    ifelse
  537.         %**************** We should copy the device here,
  538.         %**************** but since we can't close the old device,
  539.         %**************** we don't.  This is WRONG.
  540.     %****************copydevice
  541.    2 index /Policies get
  542.    .trysetparams
  543.    dup type /booleantype ne
  544.     {        % The request failed.
  545.         % Stack: ... <orig> <request> <merged> <failed> <device>
  546.         %   <Policies> true mark <name> <errorname> ...
  547. DEBUG { (Recovering.\n) print pstack flush } if
  548.       counttomark 4 add index
  549.       counttomark 2 idiv { dup 4 -2 roll put } repeat
  550.       pop pop pop
  551.         % Stack: mark ... <orig> <request> <merged> <failed> <device>
  552.         %   <Policies>
  553.       6 2 roll 3 -1 roll 4 1 roll
  554.       .applypolicies
  555.       3 -1 roll 4 1 roll 6 -2 roll
  556.       .trysetparams        % shouldn't fail!
  557.       dup type /booleantype ne
  558.        { 2 { counttomark 1 add 1 roll cleartomark } repeat
  559.          /setpagedevice load exch signalerror
  560.        }
  561.       if
  562.     }
  563.    if
  564.  
  565.         % The attempt succeeded.  Install the new device.
  566.         % Stack: mark ... <merged> <failed> <device> <eraseflag>
  567. DEBUG { (Installing.\n) print pstack flush } if
  568.  
  569.    pop 2 .endpage
  570.     { 1 true .outputpage
  571.       (>>setpagedevice, press <return> to continue<<\n) .confirm
  572.     }
  573.    if
  574.         % .setdevice clears the current page device!
  575.    .currentpagedevice pop exch
  576.    .setdevice pop
  577.    .setpagedevice
  578.  
  579.         % Merge the request into the current page device.
  580.         % Stack: mark ... <merged> <failed>
  581.    exch currentpagedevice dup length 2 index length add dict copy copy
  582.         % Initialize the default matrix, taking media matching
  583.         % into account.
  584.    .computemediasize pop initmatrix concat
  585.    dup /PageOffset .knownget
  586.     {        % Translate by the given number of 1/72" units in device X/Y.
  587.       dup 0 get exch 1 get
  588.       2 index /HWResolution get dup 1 get exch 0 get
  589.       4 -1 roll mul 72 div   3 1 roll mul 72 div
  590.       idtransform translate
  591.     }
  592.    if
  593.         % We must install the new page device dictionary
  594.         % before calling the Install procedure.
  595.    dup .setpagedevice
  596.    .setdefaultscreen    % Set the default screen before calling Install.
  597.    dup /Install .knownget { exec } if
  598.    matrix currentmatrix .setdefaultmatrix
  599.         % Erase and initialize the page.
  600.    erasepage initgraphics
  601.    .beginpage
  602.  
  603.         % Clean up, calling PolicyReport if needed.
  604.         % Stack: mark ... <failed> <merged>
  605. DEBUG { (Finishing.\n) print pstack flush } if
  606.  
  607.    exch dup length 0 ne
  608.     { 1 index /Policies get /PolicyReport get
  609.       counttomark 1 add 2 roll cleartomark
  610.       exec
  611.     }
  612.     { cleartomark
  613.     }
  614.    ifelse
  615.  
  616.  } odef
  617.  
  618. end                % level2dict
  619. .setlanguagelevel
  620.